using Microsoft.EntityFrameworkCore;
using System.Linq.Expressions;
using Common.CustomEnums;
using IRepositories;

namespace Repositories
{
	public partial class BaseRepository<TEntity>:IBaseRepository<TEntity> where TEntity : class,new()
	{
		protected readonly IUnitOfWork unitOfWork;
		private readonly DbContext dbContext;

		public BaseRepository(IUnitOfWork unitOfWork)
		{
			this.unitOfWork = unitOfWork;
			this.dbContext = unitOfWork.GetDbContext();
		}

		#region Create
        public bool Create(TEntity entity)
        {
            dbContext.Set<TEntity>().Add(entity);
            return dbContext.SaveChanges() > 0;
        }

        public bool Create(IEnumerable<TEntity> entities)
        {
            dbContext.Set<TEntity>().AddRange(entities);
            return dbContext.SaveChanges() > entities.Count();
        }

        public TEntity CreateEntity(TEntity entity)
        {
            dbContext.Set<TEntity>().Add(entity);
            dbContext.SaveChanges();
            return entity;
        }

        public IEnumerable<TEntity> CreateEntity(IEnumerable<TEntity> entities)
        {
            dbContext.Set<TEntity>().AddRange(entities);
            dbContext.SaveChanges();
            return entities;
        }
        #endregion

		#region Delete
        public bool Delete(object Id)
        {
            var entity = dbContext.Set<TEntity>().Find(Id);
            if (entity != null)
            {
                dbContext.Set<TEntity>().Remove(entity);
                dbContext.SaveChanges();
                return true;
            }
            return false;
        }

        public bool Delete(IEnumerable<object> Ids)
        {
            var count = Ids.Count();
            foreach (var id in Ids)
            {
                if (Delete(id))
                {
                    count --;
                }
            }
            return count == 0;
        }

        public bool Delete(Expression<Func<TEntity, bool>> expression)
        {
            var deleteEntities = dbContext.Set<TEntity>().Where(expression);
            var deleteCount = deleteEntities.Count();
            if (deleteCount <= 0)
            {
                return false;
            }
            dbContext.Set<TEntity>().RemoveRange(deleteEntities);
            return deleteCount > dbContext.SaveChanges();
        }
        #endregion

        #region Update
        public bool Update(TEntity entity)
        {
            dbContext.Set<TEntity>().Attach(entity).State = EntityState.Modified;
            return dbContext.SaveChanges() > 0;
        }

        public bool Update(IEnumerable<TEntity> entities)
        {
            foreach (var entity in entities)
            {
                dbContext.Set<TEntity>().Attach(entity).State = EntityState.Modified;
            }
            return dbContext.SaveChanges() == entities.Count();
        }
        #endregion
		
        #region Query
        public TEntity? Query(object Id)
        {
            return dbContext.Set<TEntity>().Find(Id);
        }

        public IQueryable<TEntity> Query()
        {
            return dbContext.Set<TEntity>().AsQueryable();
        }

        public TEntity? QueryWhere(Expression<Func<TEntity, bool>> whereExpression)
        {
            return dbContext.Set<TEntity>().FirstOrDefault(whereExpression);
        }

        public IQueryable<TEntity> Query(Expression<Func<TEntity, bool>> whereExpression)
        {
            return dbContext.Set<TEntity>().Where(whereExpression);
        }

        public IQueryable<TEntity> Query<TOrder>(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, TOrder>> orderExpression, SortOrder order = SortOrder.Ascending)
        {
            var result = dbContext.Set<TEntity>().Where(whereExpression);
            if (order == SortOrder.Ascending)
            {
                result = result.OrderBy(orderExpression);
            }
            else
            {
                result = result.OrderByDescending(orderExpression);
            }
            return result;
        }

        public IQueryable<TEntity> Query<TOrder>(Expression<Func<TEntity, bool>>? whereExpression = null, Expression<Func<TEntity, TOrder>>? orderExpression = null, SortOrder order = SortOrder.Ascending, int pageIndex = 0, int pageSize = 0)
        {
            var result = dbContext.Set<TEntity>().AsQueryable();
            if (whereExpression != null)
            {
                result = result.Where(whereExpression);
            }
            if (orderExpression != null)
            {
                if (order == SortOrder.Ascending)
                {
                    result = result.OrderBy(orderExpression);
                }
                else
                {
                    result = result.OrderByDescending(orderExpression);
                }
            }
            if (pageIndex != 0 && pageSize != 0)
            {
                result = result.Skip((pageIndex - 1) * pageSize).Take(pageSize);
            }
            return result;
        }
        #endregion

	}
}
